package com.zsh.wx_account1.controller;

import com.baidu.aip.ocr.AipOcr;
import com.thoughtworks.xstream.XStream;
import com.zsh.wx_account1.entity.Article;
import com.zsh.wx_account1.entity.NewsMessage;
import com.zsh.wx_account1.entity.TextMessage;
import com.zsh.wx_account1.util.*;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.function.Consumer;

/**
 * @Author ZhaoShuHao
 * @Date 2023/8/21 16:11
 */
@RestController
@RequestMapping("/wxTest/wx")
public class GetWxController {
    //百度AI的个人相关信息
    public static final String APP_ID = "38135852";
    public static final String API_KEY = "GimuujuwA63R1xqYtonSC3Fw";
    public static final String SECRET_KEY = "0K2bfiGowe4cEG9yvRoAr35GUG9dC4YV";
    //定义click按钮的eventKey，方便区分
    //笑话大全
    public static final String JOKES = "jokes";
    //谜语大全
    public static final String RDDLE = "rddle";
    //心灵鸡汤
    public static final String SOUP = "soup";
    /*校验信息是否来自微信服务器
    signature：微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
    timestamp： 时间戳
    nonce：随机数
    echostr：随机字符串
    * */
    @GetMapping("/")
    public String checkToken(String signature,String timestamp,String nonce,String echostr){
        // 1）将token、timestamp、nonce三个参数进⾏字典序排序
        String token = "zsh";
        List<String> list = Arrays.asList(token, timestamp, nonce);
        //排序
        Collections.sort(list);
        System.out.println("signature："+signature);
        System.out.println("list："+list);
        // 2）将三个参数字符串拼接成⼀个字符串进⾏sha1加密
        StringBuilder stringBuilder = new StringBuilder();
        list.stream().forEach(s -> stringBuilder.append(s));
        System.out.println("stringBuilder.toString()："+stringBuilder.toString());
        //加密
        try {
            MessageDigest sha1 = MessageDigest.getInstance("sha1");
            //使用sha1进行加密，获得byte[]数组
            byte[] digest = sha1.digest(stringBuilder.toString().getBytes());
            System.out.println("digest："+digest);
            System.out.println("digest.toString()："+  digest.toString());
            System.out.println("new String(digest)："+ new String(digest));
            System.out.println("Arrays.toString(digest)："+ Arrays.toString(digest));
//            String sum = integerToHexString(digest);
//            String sum = stringFormat(digest);
            String sum = integerToHexString2(digest);
            // 3）开发者获得加密后的字符串可与 signature 对⽐，标识该请求来源于微信
            if (!StringUtils.isEmpty(signature) && signature.equals(sum)) {
                System.out.println("sum："+sum);
                return echostr;
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
    //第一种方式，课程上的方式（使用Integer.toHexString）
    private String integerToHexString(byte[] digest){
        StringBuilder sum = new StringBuilder();
        for (byte b : digest) {
            sum.append(Integer.toHexString((b>>4)&15));
            sum.append(Integer.toHexString(b&15));
        }
        return sum.toString();
    }
   /* 第二种方式（字符串格式 %02xString.format()）
   * 这String.format是将字节数组转换为十六进制的最简单和明显的方法，%02x对于小写十六进制，%02X大写十六进制。
   * */
    private String stringFormat(byte[] digest){
        StringBuilder sum = new StringBuilder();
        for (byte b : digest) {
            sum.append(String.format("%02x", b));
        }
        return sum.toString();
    }
    //第三种方式（Integer.toHexString(decimal)）
    private String integerToHexString2(byte[] digest){
        StringBuilder result = new StringBuilder();
        for (byte aByte : digest) {
            int decimal = (int) aByte & 0xff;               // bytes widen to int, need mask, prevent sign extension
            // get last 8 bits
            String hex = Integer.toHexString(decimal);
            if (hex.length() % 2 == 1) {                    // if half hex, pad with zero, e.g \t
                hex = "0" + hex;
            }
            result.append(hex);
        }
        return result.toString();
    }

    //获取用户向测试号发送的消息，输出到控制台上
    /*@PostMapping("/")
    public String receiveMessage(HttpServletRequest request) throws IOException{
        ServletInputStream inputStream = request.getInputStream();
        byte[] bytes = new byte[1024];
        System.out.println("inputStream："+inputStream);
        int len = 0;
        while ((len=inputStream.read(bytes))!=-1){
            System.out.println(new String(bytes, 0, len));
        }
        return "";
    }*/
    //获取用户向测试号发送的消息，并解析,封装成map结构
    @PostMapping("/")
    public String receiveMessage(HttpServletRequest request) throws IOException{
        ServletInputStream inputStream = request.getInputStream();
        Map<String, String> map = new HashMap<>();
        //获取xml解析工具类
        SAXReader saxReader = new SAXReader();
        try {
            //读取request输⼊流，获得Document对象
            Document document = saxReader.read(inputStream);
            //获得root节点
            Element rootElement = document.getRootElement();
            //获取所有子节点
            List<Element> elements = rootElement.elements();
            elements.stream().forEach(new Consumer<Element>() {
                @Override
                public void accept(Element element) {
                    map.put(element.getName(),element.getStringValue());
                }
            });

        } catch (DocumentException e) {
            e.printStackTrace();
        }
        System.out.println("消息为："+map);
        //回复消息的格式必须为xml的格式
        //1、简单的回复
        /*String message ="<xml> " +
                "<ToUserName><![CDATA[okuVs5iLGbRWwjjotu8EsKVURyDM]]></ToUserName>" +
                " <FromUserName><![CDATA[gh_54b74a688c3b]]></FromUserName>" +
                " <CreateTime>1692685746</CreateTime> <MsgType><![CDATA[text]]>" +
                "</MsgType> <Content><![CDATA[你好]]></Content> " +
                "</xml>";*/
        //2、封装消息回复
//        String message = getReplyMessageByWord(map);

        String message = null;
        String msgType = map.get("MsgType");
        switch (msgType){
            case "text":
                if(map.get("Content").equals("图文")){
                    //回复图文信息
                    message = getReplyNewsMessage(map);
                }else {
                    //成语接龙
                    String content = IdiomJielongUtil.startIdiomJielong(map.get("Content"));
                    message = assembleTextXMLFormat(content,map);
                    //3、消息处理案例-接⼊第三⽅服务接⼝（获取同义词）
                    //message = getReplyMessageByWord(map);
                }
                break;
            case "event":
                //处理事件
                message = handleEvent(map);
                break;
            case "image":
                message=handleImage(map);
                break;
            default:
                break;
        }
        System.out.println(message);
        return message;
    }
    //2、封装消息格式
   /* private String getReplyMessageByWord(Map<String, String> map) {
        TextMessage textMessage = new TextMessage();
        textMessage.setToUserName(map.get("FromUserName"));
        textMessage.setFromUserName(map.get("ToUserName"));
        textMessage.setMsgType("text");
        textMessage.setContent("哈哈哈哈哈哈哈哈哈");
        textMessage.setCreateTime(System.currentTimeMillis()/1000);
        //XStream将Java对象转换成xml字符串
        XStream xStream = new XStream();
        xStream.processAnnotations(TextMessage.class);
        String xml = xStream.toXML(textMessage);
        return xml;
    }*/
    //封装文本text的xml结构（回复文本消息可以通用）
    private String assembleTextXMLFormat(String content,Map<String,String > map){
        TextMessage textMessage = new TextMessage();
        textMessage.setToUserName(map.get("FromUserName"));
        textMessage.setFromUserName(map.get("ToUserName"));
        textMessage.setMsgType("text");
        textMessage.setContent(content);
        textMessage.setCreateTime(System.currentTimeMillis()/1000);
        //XStream将Java对象转换成xml字符串
        XStream xStream = new XStream();
        xStream.processAnnotations(TextMessage.class);
        String xml = xStream.toXML(textMessage);
        return xml;
    }
    //3.消息处理案例-接⼊第三⽅服务接⼝(获取同义词)
    private String getReplyMessageByWord(Map<String, String> map)
    {
        String content = WordUtil.getWords(map.get("Content"));
        return assembleTextXMLFormat(content,map);
    }
    //获取图文消息
    private String getReplyNewsMessage(Map<String, String> map) {
        NewsMessage newsMessage = new NewsMessage();
        newsMessage.setToUserName(map.get("FromUserName"));
        newsMessage.setFromUserName(map.get("ToUserName"));
        newsMessage.setMsgType("news");

        newsMessage.setCreateTime(System.currentTimeMillis()/1000);
        newsMessage.setArticleCount(1);
        List<Article> articles = new ArrayList<>();
        Article article = new Article();
        article.setTitle("要开心呀的csdn个人中心");
        article.setDescription("要开心呀的csdn个人中心，个人笔记、学习记录");
                article.setUrl("https://blog.csdn.net/ZhShH0413?spm=1000.2115.3001.5343");

        article.setPicUrl("http://mmbiz.qpic.cn/sz_mmbiz_jpg/IPwvTbhAHQL1rPJgNdCuD2udSmC7icF7bFtqdOejlAIFQo9HibTFLggqtbRfObia9XP90f9gSQ2mYWApBkSjcl1lA/0");
                articles.add(article);
        newsMessage.setArticles(articles);
        //XStream将Java对象转换成xml字符串
        XStream xStream = new XStream();
        xStream.processAnnotations(NewsMessage.class);
        String xml = xStream.toXML(newsMessage);
        return xml;
    }

    /**
     * 处理事件推送
     * @param map
     * @return
     */
    private String handleEvent(Map<String, String> map) {
        String message = null;
        String event = map.get("Event");
        switch (event){
            case "CLICK":
                String eventKey = map.get("EventKey");
                if(JOKES.equals(eventKey)){
                    String s = JokesUtil.printC();
                    message =assembleTextXMLFormat(s,map);
                }else if(RDDLE.equals(eventKey)){
                    String rddle = RddleUtil.getRddle();
                    message =assembleTextXMLFormat(rddle,map);
                }else if(SOUP.equals(eventKey)){
                    String soup = SoupUtil.getSoup();
                    message =assembleTextXMLFormat(soup,map);
                }
                break;
            case "VIEW":
                message =  assembleTextXMLFormat("view",map);
                System.out.println("view");
                break;
            case "pic_photo_or_album":
                message =  assembleTextXMLFormat("pic_photo_or_album",map);
                System.out.println("pic_photo_or_album");
            case "unsubscribe":
            case "subscribe":
                message = handleSubscribe(map);
                System.out.println("subscribe");
                break;
            default:
                break;
        }
        return message;
    }

    //借用百度Api实现网络图片文字识别
    private String handleImage(Map<String, String> map) {
        // 初始化⼀个AipOcr
        AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
        // ⽹络图⽚⽂字识别, 图⽚参数为远程url图⽚
        String url = map.get("PicUrl");
        JSONObject res = client.webImageUrl(url, new HashMap<String,String>());
        System.out.println(res.toString(2));
        JSONArray wordsResult = res.getJSONArray("words_result");
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("大佬瞅我眼不眼熟：\r\n\r\n\r\n\r\n");
        Iterator<Object> iterator = wordsResult.iterator();
        while(iterator.hasNext()){
            JSONObject next = (JSONObject) iterator.next();
            stringBuilder.append(next.getString("words"));
        }
        stringBuilder.append("\r\n\r\n\r\n\r\n"+"没错，小弟我啊，还能文字识图，给个关注吧！");
        return  assembleTextXMLFormat(stringBuilder.toString(),map);
    }

    //关注事件
    private String handleSubscribe(Map<String,String > map){
        String content= "尊敬的大佬，欢迎您关注本公众号，小弟可以为您服务的有：\r\n（1）成语接龙：您只要输入一个成语，小弟就能做出回答，快来和小弟比划比划！" +
                "\r\n（2）图片文字识别：您发送一个带文字的图片，小弟就可以帮您识别文字！\r\n（3）笑话大全：可能不好笑，但小弟还是希望大佬能哈哈哈哈！" +
                "\r\n（4）谜语大全：快点来猜猜看吧，不能偷看答案哦！\r\n（5）心灵鸡汤：让小弟用鸡汤来安抚您吧，当然鸡汤可能不咋地！" +
                "\r\n大佬注意了：给小弟一个关注好不好，csdn求个关注，谢谢大佬！";
        return assembleSubscribeEnventXMLFormat(content,map);
    }

    //封装文本text的xml结构（回复文本消息可以通用）
    private String assembleSubscribeEnventXMLFormat(String content,Map<String,String > map){
        TextMessage textMessage = new TextMessage();
        textMessage.setToUserName(map.get("FromUserName"));
        textMessage.setFromUserName(map.get("ToUserName"));
        textMessage.setMsgType("text");
        textMessage.setContent(content);
        textMessage.setCreateTime(System.currentTimeMillis()/1000);
        //XStream将Java对象转换成xml字符串
        XStream xStream = new XStream();
        xStream.processAnnotations(TextMessage.class);
        String xml = xStream.toXML(textMessage);
        return xml;
    }
}
